﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PointAsLine
{
    public class PolygonContainmentChecker
    {
        /// <summary>
        /// 判断多边形A是否包含多边形B（包括90%面积覆盖的情况）
        /// </summary>
        /// <param name="polygonA">多边形A的顶点列表</param>
        /// <param name="polygonB">多边形B的顶点列表</param>
        /// <param name="coverageThreshold">覆盖阈值(0-1)，默认0.9表示90%覆盖即视为包含</param>
        /// <returns>是否满足包含条件</returns>
        public static bool IsPolygonContained(Polyline polygonA, Polyline polygonB, double coverageThreshold = 0.9)
        {
            // 1. 首先检查多边形B是否完全在多边形A内部(精确包含)
            if (IsPolygonCompletelyContained(polygonA, polygonB))
            {
                return true;
            }

            // 2. 如果不完全包含，则计算面积覆盖比例
            double areaB = polygonB.ComputeArea();
            if (areaB == 0) return false; // 避免除以零

            double coveredArea = CalculateCoveredArea(polygonA, polygonB);
            double coverageRatio = (double)coveredArea / areaB;

            // 3. 判断覆盖比例是否达到阈值
            return coverageRatio >= coverageThreshold;
        }

        /// <summary>
        /// 精确判断多边形B是否完全在多边形A内部
        /// </summary>
        private static bool IsPolygonCompletelyContained(Polyline polygonA, Polyline polygonB)
        {
            // 检查多边形B的所有顶点是否都在多边形A内部
            foreach (var point in polygonB.Points)
            {
                if (!polygonA.IsPointInPolygon(point))
                {
                    return false;
                }
            }

            // 额外检查多边形B的边是否与多边形A相交(防止边交叉情况)
            for (int i = 0; i < polygonB.Count; i++)
            {
                PointF2G p1 = polygonB[i];
                PointF2G p2 = polygonB[(i + 1) % polygonB.Count];

                if (DoesLineSegmentIntersectPolygon(polygonA, p1, p2))
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 计算多边形B被多边形A覆盖的面积
        /// </summary>
        private static double CalculateCoveredArea(Polyline polygonA, Polyline polygonB)
        {
            // 方法1：使用多边形裁剪算法(如Weiler-Atherton)计算交集面积
            // 这里简化实现，使用蒙特卡洛方法估算(适用于复杂情况)

            // 获取多边形的边界框
            RectangleF boundsA = polygonA.GetBoundingBox();
            RectangleF boundsB = polygonB.GetBoundingBox();
            RectangleF totalBounds = new RectangleF(
                Math.Min(boundsA.Left, boundsB.Left),
                Math.Min(boundsA.Top, boundsB.Top),
                Math.Max(boundsA.Right, boundsB.Right) - Math.Min(boundsA.Left, boundsB.Left),
                Math.Max(boundsA.Bottom, boundsB.Bottom) - Math.Min(boundsA.Top, boundsB.Top));

            // 蒙特卡洛采样点数(可根据精度需求调整)
            int sampleCount = 10000;
            int pointsInsideBoth = 0;

            Random random = new Random();
            for (int i = 0; i < sampleCount; i++)
            {
                // 在总边界框内随机采样
                float x = (float)(totalBounds.Left + random.NextDouble() * totalBounds.Width);
                float y = (float)(totalBounds.Top + random.NextDouble() * totalBounds.Height);

                PointF2G samplePoint = new PointF2G(x, y);

                // 检查点是否同时在两个多边形内
                if (polygonA.IsPointInPolygon(samplePoint) && polygonB.IsPointInPolygon(samplePoint))
                {
                    pointsInsideBoth++;
                }
            }

            // 计算覆盖面积比例
            float totalArea = totalBounds.Width * totalBounds.Height;
            float coveredRatio = (float)pointsInsideBoth / sampleCount;
            return coveredRatio* totalArea;
        }

        

        /// <summary>
        /// 判断线段是否与多边形相交
        /// </summary>
        private static bool DoesLineSegmentIntersectPolygon(Polyline polygon, PointF2G p1, PointF2G p2)
        {
            int n = polygon.Count;
            for (int i = 0; i < n; i++)
            {
                PointF2G q1 = polygon[i];
                PointF2G q2 = polygon[(i + 1) % n];

                if (DoLineSegmentsIntersect(p1, p2, q1, q2))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 判断两条线段是否相交
        /// </summary>
        private static bool DoLineSegmentsIntersect(PointF2G p1, PointF2G p2, PointF2G q1, PointF2G q2)
        {
            // 计算方向
            float d1 = Direction(q1, q2, p1);
            float d2 = Direction(q1, q2, p2);
            float d3 = Direction(p1, p2, q1);
            float d4 = Direction(p1, p2, q2);

            // 如果线段跨立，则相交
            if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&
                ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0)))
            {
                return true;
            }

            // 检查共线情况
            if (d1 == 0 && OnSegment(q1, q2, p1)) return true;
            if (d2 == 0 && OnSegment(q1, q2, p2)) return true;
            if (d3 == 0 && OnSegment(p1, p2, q1)) return true;
            if (d4 == 0 && OnSegment(p1, p2, q2)) return true;

            return false;
        }

        /// <summary>
        /// 计算三点方向
        /// </summary>
        private static float Direction(PointF2G pi, PointF2G pj, PointF2G pk)
        {
            return (pk.X - pi.X) * (pj.Y - pi.Y) - (pj.X - pi.X) * (pk.Y - pi.Y);
        }

        /// <summary>
        /// 检查点是否在线段上
        /// </summary>
        private static bool OnSegment(PointF2G pi, PointF2G pj, PointF2G pk)
        {
            return Math.Min(pi.X, pj.X) <= pk.X && pk.X <= Math.Max(pi.X, pj.X) &&
                   Math.Min(pi.Y, pj.Y) <= pk.Y && pk.Y <= Math.Max(pi.Y, pj.Y);
        }

        
    }

}
